package com.lopo.pagehelper;

import com.beust.jcommander.ParameterException;
import com.github.houbb.asm.tool.reflection.AsmMethods;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import groovy.util.logging.Slf4j;
import lombok.SneakyThrows;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.binding.MapperMethod;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.StandardReflectionParameterNameDiscoverer;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;

@Aspect
@Component
@Slf4j
public class PaginationAspect {
    protected static Map<String, String> PARAMS = new HashMap(6, 1.0F);
    private boolean hasParamAnnotation;
    private SortedMap<Integer, String> names;
    private static final String GENERIC_NAME_PREFIX = "param";

    /**
     * 定义切入点
     */
    @Pointcut("@annotation(com.lopo.pagehelper.Pagination)")
    public void access() {
    }

    @SneakyThrows
    @Around("access()")
    public Object around(ProceedingJoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        Object[] args = joinPoint.getArgs();
        final ParamNameResolver paramNameResolver = new ParamNameResolver();
        paramNameResolver.pp(method);
        Pagination pagination = getPaginationAnnotation(method);
        Map<String, Object> map = getFieldsName(method, args);
        startPage(pagination.pageNo(), pagination.pageSize(), map);
        Object result = joinPoint.proceed(args);
        // 返回的数据类型要保证和注解方法上的一致
        return result;
    }

    /**
     * 获取方法的所有参数
     *
     * @param
     * @return
     */
    private static HashMap<String, Object> getFieldsName(Method method, Object[] args) {
        final HashMap<String, Object> map = new HashMap<>();
        // 请求的方法参数名称
        ParameterNameDiscoverer u = new StandardReflectionParameterNameDiscoverer();
        String[] paramNames = u.getParameterNames(method);
        if (args != null && paramNames != null) {
            for (int i = 0; i < args.length; i++) {
                map.put(paramNames[i], args[i]);
            }
        }
        return map;
    }

    /**
     * 获取Pagination注解
     *
     * @param method
     * @return
     */
    public Pagination getPaginationAnnotation(Method method) {
        Pagination pagination = method.getAnnotation(Pagination.class);
        return pagination;
    }

    /**
     * 开始分页
     */
    private void startPage(String pageNoParameterName, String pageSizeParameterName, Map<String, Object> map) {
        // 获取pageNo和pageSize
        Integer pageNumber = (Integer) map.get(pageNoParameterName);
        Integer pageSize = (Integer) map.get(pageSizeParameterName);
        if (pageNumber == null || pageSize == null) {
            throw new ParameterException("pageNumber Or pageSize is null");
        }
        PageHelper.startPage(pageNumber, pageSize);
    }

    /**
     * 对分页结果进行包装 如果分页成功则会返回PageResult
     *
     * @param result
     */
    private Object pageResult(Object result) {
        PageInfo pageInfo = null;
        Response response;
        PageResponse data = null;
        if (result instanceof Response) {
            response = (Response) result;
            data = (PageResponse) response.getData();
            if (data.getRows() instanceof List) {
                pageInfo = new PageInfo((List) data.getRows());
            }
        } else if (result instanceof PageResponse) {
            data = (PageResponse) result;
            if (data.getRows() instanceof List) {
                pageInfo = new PageInfo((List) data.getRows());
            }
        }
        if (pageInfo != null) {
            data.setPageNumber((long) pageInfo.getPageNum());
            data.setPageSize((long) pageInfo.getPageSize());
            data.setTotal(pageInfo.getTotal());
            return Response.success(data);
        }
        return result;
    }
}